#include <SubSystemBase/SubSystemManager.h>
#include <cstring>

SubSystemManager::SubSystemManager()
{
	m_logger = new NullLogger();	//Use NullLogger by default, nothing will be logged
	m_subSystemsStarted = false;
}

SubSystemManager::~SubSystemManager()
{
	this->shutdownEnvironment();
	m_subSystems.clear();
	m_subSystemsStarted = false;
	if(m_logger)
	{
		m_logger->system("SubSystemManager terminating");
		delete m_logger;
	}
}

SubSystemManager* SubSystemManager::getInstance()
{
	static SubSystemManager* manager = new SubSystemManager();
	return manager;
}


void SubSystemManager::startEnvironment()
{
	try
	{
		if(!m_subSystemsStarted)
		{
			m_logger->system("SubSystemManager: Starting environment...");

			SubSystem_vec_iter end = m_subSystems.end();

			for(SubSystem_vec_iter it = m_subSystems.begin(); it != end; ++it)
			{
				std::string msg = "Starting subsystem: ";
				msg += (*it)->getName();
				m_logger->info(msg);

				if((*it)->initialize() == false)
				{
					msg = "Failed to initialize ";
					msg += (*it)->getName();
					throw new Exception(msg);
				}
			}

			m_subSystemsStarted = true;
		}
	}
	catch(Exception* e)
	{
		m_logger->system("Caught exception while initializing subsystem: ");
		if(e->hasCause())
		{
			m_logger->critical(e->cause);
		}
		m_logger->critical("Subsystem failure, shutting down");

		terminate(1);	//Terminate with error code
	}
}



void SubSystemManager::shutdownEnvironment()
{
	m_logger->system("SubSystemManager: Shutting down environment...");

	for(int i = m_subSystems.size()-1; i >= 0; i--)
	{
		std::string msg = "SubSystemManager: Shutting down subsystem: ";
		msg += m_subSystems[i]->getName();
   		m_logger->info(msg);
   		m_subSystems[i]->shutdown();
	}

	m_subSystemsStarted = false;
}

ISubSystem* SubSystemManager::getSubSystemByName(const char* subSystemName)
{
	for(size_t i = 0; i < m_subSystems.size(); i++)
	{
		if(strcmp(subSystemName, m_subSystems[i]->getName()) == 0)
		{
			return m_subSystems[i];
		}
	}
	return 0;
}

void SubSystemManager::unregisterSubSystem(const char* subSystemName, bool shutDownFirst)
{
	for(SubSystem_vec_iter it = m_subSystems.begin(); it != m_subSystems.end(); it++)
	{
		if(subSystemName == (*it)->getName())
		{
			if(shutDownFirst && ((*it)->isInitialized() == true))
			{
				(*it)->shutdown();
			}

			m_subSystems.erase(it);
			return;
		}
	}

	std::string msg = "Tried to unregister non-existing subsystem: ";
	msg += subSystemName;
	m_logger->warn(msg);
}

void SubSystemManager::registerSubSystem(ISubSystem& subSystem)
{
	std::string msg = "Registering subsystem: ";
	msg += subSystem.getName();
	m_logger->debug(msg);

	if(getSubSystemByName(subSystem.getName()) != 0)
	{
		msg = "Subsystem already registered: ";
		msg += subSystem.getName();
		m_logger->warn(msg);
		//TODO
		//throw new Exception("Another subsystem with the same name already exists!");
	}
	m_subSystems.push_back(&subSystem);

	subSystem.setLogger(m_logger);
}


void SubSystemManager::setLogger(ILogger* logger)
{
	if(logger)
	{
		if(m_logger)
		{
			m_logger->debug("SubSystemManager: Replacing logger");
			delete m_logger;
			m_logger = 0;
		}
		m_logger = logger;

		m_logger->debug("SubSystemManager: got new Logger, setting it to subsystems");

		for(size_t i = 0; i < m_subSystems.size(); i++)
		{
			m_subSystems[i]->setLogger(m_logger);
		}
	}
	else
	{
		if(m_logger)
		{
			m_logger->warn("Trying to set null-pointer as logger for SubSystemManager, ignored");
		}
	}
}

void SubSystemManager::terminate(int exitValue)
{
	 delete getInstance();	//Calls the destructor to get proper shutdown
	 exit(exitValue);
}
